﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.TextTemplating;
using Microsoft.VisualStudio.TextTemplating.VSHost;
using ScaffoldIt.Configuration;
using System.Text;
using ScaffoldIt.Helpers;
using ScaffoldIt.Commands;

namespace ScaffoldIt
{
    class ScaffoldingContext
    {
        public bool Force { get; set; }

        public bool HasErrors
        {
            get
            {
                return Errors.Count > 0;
            }
        }

        private List<ScaffoldingError> errors = new List<ScaffoldingError>();

        public List<ScaffoldingError> Errors
        {
            get
            {
                return this.errors;
            }
            set
            {
                this.errors = value;
            }
        }

        public EnvDTE80.DTE2 DTE { get; private set; }

        private ScaffoldingEngine Engine { get; set; }
        
        public ScaffoldItConfig Config { get; private set; }        

        public string SolutionFolder { get; private set; }

        public VsOutputWriter Output { get; private set; }

        public IEnumerable<Template> Templates { get; set; }

        public IEnumerable<Parameter> Parameters { get; set; }

        public TextTemplatingSession Session { get; private set; }
        
        public string ErrorSummary
        {
            get
            {
                StringBuilder sb = new StringBuilder();
                foreach (var err in Errors)
                {
                    sb.AppendLine(err.ToString());
                }
                return sb.ToString();
            }
        }
        
        public ScaffoldingContext()
        {
            DTE = (EnvDTE80.DTE2)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(Microsoft.VisualStudio.Shell.Interop.SDTE));
            
            SolutionFolder = Path.GetDirectoryName(DTE.Solution.FileName);
            Config = DTE.GetConfig();
            Output = new VsOutputWriter("Scaffold it !");
            Engine = new ScaffoldingEngine(DTE, Output, Errors);
            Session = new TextTemplatingSession();
            Output.WriteLine("############# Scaffold it ! has changed a bit, it now use a Model Parameter of type ScaffoldIt.ScaffoldModel, use \"create scaffolding environment\" to see a sample of the new template format");
        }

        public bool Init()
        {
            Templates = FormTemplateSelection.GetTemplates(this);
            if (Templates == null || Templates.Count() == 0)
                return false;

            var parameters = Templates.GetParameters(this).ToList();
            if (parameters.Count > 0)
            {
                Parameters = FormParameters.GetParameters(parameters);
                if (Parameters == null) //User click cancel
                    return false;
            }

            Session.Apply(parameters);

            return true;
        }

        public string ApplyTemplate(string templateFile)
        {
            return Engine.ApplyTemplate(templateFile);
        }

        public void Scaffold(IEnumerable<ScaffoldModel> models)
        {
            bool errors = false;
            foreach (var model in models)
            {
                errors = ScaffoldModel(model, errors);
                if (errors) 
                    break;
            }

            if (errors)
            {
                CommandSet.ShowMessage("Scaffolding has some error or warnings, please check Output window for more details");
                Output.WriteLine("#### !!! READ ME !!! #### Scaffold it ! has changed a bit, templates now use a Parameter names Model of type ScaffoldIt.ScaffoldModel, use \"create scaffolding environment\" to see a sample of the new template format");
            }
        }

        private bool ScaffoldModel(ScaffoldModel model, bool errors)
        {
            Output.WriteLine("########## scaffolding " + model.FullName + " at " + DateTime.Now.ToString());
            Errors.Clear();
            Session["Model"] = model;
            Engine.InitTemplateContext(Session);

            foreach (var template in Templates)
            {
                Output.WriteLine("## scaffold with '" + template.Name + "' (" + template.TemplateName + ") to project " + template.ProjectName);
                template.ApplyTemplate(this, model);
            }

            if (!HasErrors)
            {
                foreach (var template in Templates)
                {
                    template.OutputTemplate(this);
                }
            }
            else
            {
                Output.WriteLine("Files generation cancelled because of errors");
                errors = true;
            }

            return errors;
        }
    }
}
